﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using MIDIRemapper.DeviceInterfaces;
using MIDIRemapper;

namespace Midi
{
    public partial class RouteForm : Form
    {
        public Transformable Result
        {
            get;
            private set;
        }

        public RouteForm()
        {
            InitializeComponent();

            //Populate ComboBoxes
            channelInSelect.Items.Clear();
            channelOutSelect.Items.Clear();

            channelInSelect.Items.Add("All");
            channelOutSelect.Items.Add("All");
            PopulateValueIn();
            PopulateValueOut();
            for (int i = 1; i <= 16; i++)
            {
                channelInSelect.Items.Add(i.ToString());
                channelOutSelect.Items.Add(i.ToString());
            }

            channelInSelect.SelectedIndex = 0;
            channelOutSelect.SelectedIndex = 0;
            valueInSelect.SelectedIndex = 0;
            valueOutSelect.SelectedIndex = 0;
        }

        private void PopulateValueIn()
        {
            valueInSelect.Items.Clear();
            valueInSelect.Items.Add("All");
            for (int i = 0; i <= 127; i++)
            {
                valueInSelect.Items.Add(i.ToString());
            }
        }
        private void PopulateValueOut()
        {
            valueOutSelect.Items.Clear();
            valueOutSelect.Items.Add("All");
            for (int i = 0; i <= 127; i++)
            {
                valueOutSelect.Items.Add(i.ToString());
            }
        }

        public void DisplayStatus(string status)
        {
            MessageBox.Show(status);
        }

        #region Routing selection handlers
        private void addRouteButton_Click(object sender, EventArgs e)
        {
            if (typeInSelect.SelectedItem == null)
            {
                DisplayStatus("Please select an input type which you wish to route.");
                return;
            }
            if (typeOutSelect.SelectedItem == null)
            {
                DisplayStatus("Please select an output type for the signal to be routed to.");
                return;
            }

            try
            {
                Result = new Transformable(
                        typeInSelect.Text.GetMidiType(),
                        typeOutSelect.Text.GetMidiType(),
                        programIn: TypeGetter.ParseMidiNum(itemInSelect.Text),
                        programOut: TypeGetter.ParseMidiNum(itemOutSelect.Text),
                        valueIn: TypeGetter.ParseMidiNum(valueInSelect.Text),
                        valueOut: TypeGetter.ParseMidiNum(valueOutSelect.Text),
                        channelIn: TypeGetter.ParseMidiNum(channelInSelect.Text),
                        channelOut: TypeGetter.ParseMidiNum(channelOutSelect.Text),
                        transpose: (int)transposeSelect.Value,
                        switchData: switchSelectBox.Checked);
            }
            catch (InvalidCastException)
            {
                DisplayStatus("Invalid value given.");
                return;
            }

            this.DialogResult = System.Windows.Forms.DialogResult.OK;
            this.Close();
        }

        private void typeInSelect_SelectionChangeCommitted(object sender, EventArgs e)
        {
            itemInSelect.Items.Clear();

            //Pitch Wheel is a single-program type and cannot be routed to all programs.
            itemInSelect.Items.Add(
                (((string)typeOutSelect.SelectedItem).GetMidiType() == MidiType.Pitch_Wheel) ?
                "Random" : "All");

            //Instrument is a single-value type and cannot be routed to all values
            valueOutSelect.Items[0] =
                (((string)typeOutSelect.SelectedItem).GetMidiType() == MidiType.Instrument ? "Random" : "All");

            if (!itemInSelect.Enabled) itemInSelect.Enabled = true;
            if (!valueInSelect.Enabled) valueInSelect.Enabled = true;

            if (((string)typeInSelect.SelectedItem).GetMidiType() == MidiType.Control)
            {
                for (int i = 0; i < 128; i++)
                {
                    itemInSelect.Items.Add(String.Concat(i.ToString("D3"), " ", ((Midi.Control)i).Name()));
                }
            }
            if (((string)typeInSelect.SelectedItem).GetMidiType() == MidiType.Instrument)
            {
                for (int i = 0; i < 128; i++)
                {
                    itemInSelect.Items.Add(String.Concat(i.ToString("D3"), " ", ((Midi.Instrument)i).Name()));
                }
                valueInSelect.Enabled = false;
                valueOutSelect.Items[0] = "Random"; //Overwrites "All"
            }
            if (((string)typeInSelect.SelectedItem).GetMidiType() == MidiType.Note_On)
            {
                for (int i = 0; i < 128; i++)
                {
                    itemInSelect.Items.Add(String.Concat(i.ToString("D3") + " " + TypeGetter.GetStringNote(i)));
                }
            }
            if (((string)typeInSelect.SelectedItem).GetMidiType() == MidiType.Note_Off)
            {
                for (int i = 0; i < 128; i++)
                {
                    itemInSelect.Items.Add(String.Concat(i.ToString("D3") + " " + TypeGetter.GetStringNote(i)));
                }
            }
            if (((string)typeInSelect.SelectedItem).GetMidiType() == MidiType.Pitch_Wheel)
            {
                itemInSelect.Items[0] = "N/A"; //Overwrites "All"
                itemInSelect.Enabled = false;
            }

            itemInSelect.SelectedIndex = 0;
        }

        private void typeOutSelect_SelectionChangeCommitted(object sender, EventArgs e)
        {
            itemOutSelect.Items.Clear();

            itemOutSelect.Items.Add("All");

            if (!itemOutSelect.Enabled) itemOutSelect.Enabled = true;
            if (!valueOutSelect.Enabled) valueOutSelect.Enabled = true;

            if (((string)typeOutSelect.SelectedItem).GetMidiType() == MidiType.Control)
            {
                for (int i = 0; i < 128; i++)
                {
                    itemOutSelect.Items.Add(String.Concat(i.ToString("D3"), " ", ((Midi.Control)i).Name()));
                }
            }
            if (((string)typeOutSelect.SelectedItem).GetMidiType() == MidiType.Instrument)
            {
                for (int i = 0; i < 128; i++)
                {
                    itemOutSelect.Items.Add(String.Concat(i.ToString("D3"), " ", ((Midi.Instrument)i).Name()));
                }
                valueOutSelect.Enabled = false;
            }
            if (((string)typeOutSelect.SelectedItem).GetMidiType() == MidiType.Note_On)
            {
                for (int i = 0; i < 128; i++)
                {
                    itemOutSelect.Items.Add(String.Concat(i.ToString("D3") + " " + TypeGetter.GetStringNote(i)));
                }
            }
            if (((string)typeOutSelect.SelectedItem).GetMidiType() == MidiType.Note_Off)
            {
                for (int i = 0; i < 128; i++)
                {
                    itemOutSelect.Items.Add(String.Concat(i.ToString("D3") + " " + TypeGetter.GetStringNote(i)));
                }
            }
            if (((string)typeOutSelect.SelectedItem).GetMidiType() == MidiType.Pitch_Wheel)
            {
                itemOutSelect.Items[0] = "N/A"; //Overwrites "All"
                itemOutSelect.Enabled = false;
            }

            itemOutSelect.SelectedIndex = 0;
        }

        #endregion

        #region User input watchers
        private void checkValueText(object sender, EventArgs e)
        {
            ComboBox thisBox = (ComboBox)sender;
            int thisValue;

            try { thisValue = TypeGetter.ParseMidiNum(thisBox.Text); }
            //Forget about other invalid values. We'll handle them when user presses "Add"
            catch (InvalidCastException) { return; }

            if (thisValue > 127)
            {
                thisBox.Text = "127";
                toolTip1.Show("Please select a number between 0 and 127", thisBox, 0, 18, 1500);
            }
            else if (thisValue < -1)
            {
                thisBox.Text = "0";
                toolTip1.Show("Please select a number between 0 and 127", thisBox, 0, 18, 1500);
            }

        }

        private void checkChannelText(object sender, EventArgs e)
        {
            ComboBox thisBox = (ComboBox)sender;
            int thisValue;

            try { thisValue = TypeGetter.ParseMidiNum(thisBox.Text); }

            //Forget about other invalid values. We'll handle them when user presses "Add"
            catch (InvalidCastException) { return; }

            if (thisValue > 16)
            {
                thisBox.Text = "16";
                toolTip1.Show("Please select a number between 1 and 16", thisBox, 0, 18, 1500);
            }
            else if (thisValue <= 0 && thisValue != -1)
            {
                thisBox.Text = "1";
                toolTip1.Show("Please select a number between 1 and 16", thisBox, 0, 18, 1500);
            }
        }

        /// <summary>
        /// Disable user input of letters
        /// </summary>
        private void checkKeyPressed(object sender, KeyPressEventArgs e)
        {
            ComboBox thisBox = (ComboBox)sender;
            if (e.KeyChar == 'a' || e.KeyChar == 'A')
            {
                thisBox.Text = "All";
                e.Handled = true;
            }
            else if (!char.IsNumber(e.KeyChar))
            {
                toolTip1.Show("Please type a number or press 'A' for All", thisBox, 0, 18, 1500);
                e.Handled = true;
            }
        }
        #endregion
    }
}
